﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using BobcatMultiTouch;

namespace Sample1_SimpleDrawing
{
    /// <summary>
    /// This sample demonstrates some simple drawing using inputs from the 
    /// MultiTouchInputManager (MTIM) and MultiTouchInputClient (MTIC). Lines 
    /// are drawn on the screen in different colors depending on which input 
    /// source they come from.
    /// </summary><remarks>
    /// The MTIM and MTIC work together to get the input events to your code. The 
    /// MTIM aggregates the inputs from the different sources (in this case the
    /// mouse and the Wiimote IR). The MTIC then passes the events to the form,
    /// making sure that they are marshaled to the correct GUI thread and translates
    /// the touch coordinates into client coordinates for the form.
    /// 
    /// The MTIM manages multiple input sources, and these are loaded from an 
    /// XML config file.
    /// </remarks>
    public partial class Form1 : Form
    {
        #region Public methods

        /// <summary>
        /// Constructor.
        /// </summary>
        public Form1()
        {
            InitializeComponent();
        }

        #endregion

        #region Private functions

        /// <summary>
        /// Called when the form is loaded. We initialize the MTIM and MTIC and register 
        /// for touch events.
        /// </summary>
        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {
                // We intialize the MTIM...
                MultiTouchInputManager.getInstance().initializeFromFile(CONFIG_FILENAME);
            }
            catch (Exception ex)
            {
                // The MTIM can throw exceptions in initializeFromFile if one or more sources cannot be activated...
                MessageBox.Show(ex.Message);
            }

            // We initialize the MTIC that will raise events into this form.
            // Note: We do this outside the try-catch block above as we want to receive events
            //       even if not all the sources are available - we still want to get them from the
            //       ones that are.
            m_MTIC.initialize(this);
            m_MTIC.TouchDownEvent += onTouchDown;
            m_MTIC.TouchUpEvent += onTouchUp;
            m_MTIC.TouchMoveEvent += onTouchMove;
        }

        /// <summary>
        /// Called when the form is about to close.
        /// </summary>
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            // We close the MTIC and MTIM...
            m_MTIC.close();
            MultiTouchInputManager.getInstance().close();
        }

        /// <summary>
        /// Called when the 'Edit multi-touch settings...' button is pressed.
        /// </summary>
        private void cmdMultiTouchConfig_Click(object sender, EventArgs e)
        {
            // We show the multi-touch config screen, and then save any changed config...
            MultiTouchInputManager.getInstance().showConfigScreen();
            MultiTouchInputManager.getInstance().saveToFile(CONFIG_FILENAME);
        }

        /// <summary>
        /// Called when we receive a touch-down event.
        /// </summary>
        private void onTouchDown(object sender, TouchArgs args)
        {
            // We draw a dot at the touch position...
            Point clientPoint = args.ClientPosition;
            Point destinationPoint = new Point(clientPoint.X + 1, clientPoint.Y);

            // We show it in the correct color for this source...
            Pen pen = getPen(args.PointIndex);
            Graphics g = getGraphics();
            g.DrawLine(pen, clientPoint, destinationPoint);

            // We store this point...
            m_mapPreviousPoints[args.PointIndex] = clientPoint;

        }

        /// <summary>
        /// Called when we receive a touch-up event. 
        /// </summary>
        private void onTouchUp(object sender, TouchArgs args)
        {
            // We remove the previous point entry for this source. (Otherwise we
            // would always draw an unwanted line between different unconnected lines.)
            m_mapPreviousPoints.Remove(args.PointIndex);
        }

        /// <summary>
        /// Called when we get a touch-move event. We draw a line between the previous
        /// point for this source and the new point.
        /// </summary>
        private void onTouchMove(object sender, TouchArgs args)
        {
            // We get the previous point and draw a line to the current point...
            bool bGotPreviousPoint = m_mapPreviousPoints.ContainsKey(args.PointIndex);
            if (bGotPreviousPoint == false)
            {
                return;
            }
            Point previousPoint = m_mapPreviousPoints[args.PointIndex];

            // We get the touch position...
            Point clientPoint = args.ClientPosition;

            // We draw a line betweeb the two points in the color for this source...
            Pen pen = getPen(args.PointIndex);
            Graphics g = getGraphics();
            g.DrawLine(pen, previousPoint, clientPoint);

            // We store the new point...
            m_mapPreviousPoints[args.PointIndex] = clientPoint;
        }

        /// <summary>
        /// Returns the Graphics object used for drawing onto the screen.
        /// </summary>
        private Graphics getGraphics()
        {
            Graphics g = CreateGraphics();
            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
            return g;
        }
        
        /// <summary>
        /// We get a pen for the source-index passsed in. This lets us show multiple lines
        /// in a consistent color.
        /// </summary>
        private Pen getPen(int iPointIndex)
        {
            Color color;
            switch (iPointIndex)
            {
                case 0:
                    color = Color.Red;
                    break;

                case 1:
                    color = Color.Blue;
                    break;

                case 2:
                    color = Color.Green;
                    break;

                case 3:
                    color = Color.Yellow;
                    break;

                case 4:
                    color = Color.Orange;
                    break;

                default:
                    color = Color.Black;
                    break;
            }

            Pen pen = new Pen(color);
            pen.Width = 5;
            pen.StartCap = System.Drawing.Drawing2D.LineCap.Round;
            pen.EndCap = System.Drawing.Drawing2D.LineCap.Round;

            return pen;
        }

        #endregion

        #region Private data

        // File that stores XML config about which sources are used, wiimote calibration etc...
        private const string CONFIG_FILENAME = "MultiTouchConfig.xml";

        // This object manages multi-touch events for this form...
        private MultiTouchInputClient m_MTIC = new MultiTouchInputClient();
        
        // Holds the previous values the positions for each source so 
        // that we can connect them with lines...
        private IDictionary<int, Point> m_mapPreviousPoints = new Dictionary<int, Point>();

        #endregion


    }
}
